// Copyright  Author(https://github.com/LiuShuKu). All Rights Reserved.

// Copyright (c)  2024 LiuShuKu
// Project Name :   balance
// Author       :   liushuku@yeah.net

// Package tron 交易方法.
package tron

import (
	"context"
	"crypto/ecdsa"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/fbsobreira/gotron-sdk/pkg/proto/api"
	"github.com/fbsobreira/gotron-sdk/pkg/proto/core"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/shopspring/decimal"
	"google.golang.org/protobuf/proto"
	"tronServer/internal/model/domain"
)

type transaction struct {
}

var Transaction = &transaction{}

// Trx 交易
func (t *transaction) Trx(ctx context.Context, detail *domain.TronTransactionDetail) (txId string, err error) {
	return t.transfer(ctx, detail, typeTrx)
}

// Usdt 交易
func (t *transaction) Usdt(ctx context.Context, detail *domain.TronTransactionDetail) (txId string, err error) {
	return t.transfer(ctx, detail, typeUsdt)
}

// transfer 转账核心逻辑
func (t *transaction) transfer(ctx context.Context, detail *domain.TronTransactionDetail, transferType int) (txId string, err error) {
	var (
		grpcClient     *tronGrpcs
		transfer       *api.TransactionExtention
		transactionOut *core.Transaction
		amount         decimal.Decimal
		hashKeyFrom    string
	)
	// 地址检测
	{
		{
			// 解析秘钥
			if hashKeyFrom, err = Tron.GetTrc20AddressByPrivateKey(ctx, detail.HashKey); err != nil {
				return
			}
			if detail.From != hashKeyFrom {
				err = gerror.New("秘钥与From地址不匹配")
				return
			}
		}
		{
			if err = Tron.CheckTrc20Address(ctx, detail.To); err != nil {
				err = gerror.New("接受者地址错误")
				return
			}
		}
	}
	// 处理金额
	{
		amount, err = decimal.NewFromString(detail.Amount)
		if err != nil {
			err = gerror.New("金额格式错误")
			return
		}
		if amount.IsZero() {
			err = gerror.New("金额数据错误")
			return
		}
		amount = amount.Mul(decimal.NewFromInt(tronUnit))
	}
	// 获取 grpcClient
	if grpcClient, err = tronGrpc.connect(ctx); err != nil {
		return
	}
	// 关闭 grpcClient
	defer func() {
		grpcClient.stop()
	}()
	// 转账
	switch transferType {
	case typeUsdt: // USDT
		{
			if transfer, err = grpcClient.grpc.TRC20Send(detail.From, detail.To, contract, amount.BigInt(), feeLimit); err != nil {
				return
			}
		}
	case typeTrx: // TRX
		{
			if transfer, err = grpcClient.grpc.Transfer(detail.From, detail.To, amount.IntPart()); err != nil {
				return
			}
		}
	}
	// 签名
	if transactionOut, err = t.signTransaction(transfer.Transaction, detail.HashKey); err != nil {
		return
	}
	// 广播
	if err = t.broadcastTransaction(transactionOut, grpcClient); err != nil {
		return
	}
	// 交易Id
	txId = bytesToHexString(transfer.Txid)
	return
}

// SignTransaction 签名交易
func (t *transaction) signTransaction(transaction *core.Transaction, privateKey string) (transactionOut *core.Transaction, err error) {
	var (
		privateKeyBytes []byte
		private         *ecdsa.PrivateKey
		rawData         []byte
		signature       []byte
	)
	// 解析私钥
	{
		if privateKeyBytes, err = hex.DecodeString(privateKey); err != nil {
			err = fmt.Errorf("hex decode private key error: %v", err)
			return
		}
	}
	// 加载私钥
	{
		private = crypto.ToECDSAUnsafe(privateKeyBytes)
	}
	// 释放私钥
	{
		defer func(private *ecdsa.PrivateKey) {
			b := private.D.Bits()
			for i := range b {
				b[i] = 0
			}
		}(private)
	}
	// 解析proto
	{
		if rawData, err = proto.Marshal(transaction.GetRawData()); err != nil {
			err = fmt.Errorf("proto marshal tx raw data error: %v", err)
			return
		}
	}
	// 签名数据
	{
		h256h := sha256.New()
		h256h.Write(rawData)
		hash := h256h.Sum(nil)
		if signature, err = crypto.Sign(hash, private); err != nil {
			err = fmt.Errorf("sign error: %v", err)
			return
		}
		transaction.Signature = append(transaction.Signature, signature)
	}
	return transaction, nil
}

// BroadcastTransaction 广播交易
func (t *transaction) broadcastTransaction(transaction *core.Transaction, grpcClient *tronGrpcs) (err error) {
	var (
		result *api.Return
	)
	// 重连检查
	{
		if err = grpcClient.keepConnect(); err != nil {
			return
		}
	}
	// 开始广播
	{
		if result, err = grpcClient.grpc.Broadcast(transaction); err != nil {
			err = fmt.Errorf("广播失败: %v", err.Error())
			return
		}
	}
	// 状态错误
	{
		if result.Code != 0 {
			err = fmt.Errorf("广播失败 : %v", string(result.GetMessage()))
			return
		}
	}
	// 状态错误
	{
		if !result.Result {
			o, _ := json.Marshal(result)
			err = fmt.Errorf("广播失败 : %v", string(o))
			return
		}
	}
	return
}
